<?php
//-------------------------------------------------------------------------
// OVIDENTIA http://www.ovidentia.org
// Ovidentia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or (at your option)
// any later version.
// 
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
//-------------------------------------------------------------------------
/**
 * @license http://opensource.org/licenses/gpl-license.php GNU General Public License (GPL)
 * @copyright Copyright (c) 2008 by CANTICO ({@link http://www.cantico.fr})
 */
include_once 'base.php';



/**
 * Constructs a Widget_Color.
 * @return Widget_Color
 */
function Widget_Color()
{
	return new Widget_Color();
}


/**
 * The Widget_Color class can be used to manipulate colors.
 */
class Widget_Color
{
	private $color 			= null;
	private $color_method 	= 'RVB';
	
	
	private function hue($m1, $m2, $h)
	{
		if ($h < 0) { $h = $h+1; }
		if ($h > 1) { $h = $h-1; }
		if ($h * 6 < 1) { return $m1 + ($m2 - $m1) * $h * 6; }
		if ($h*2 < 1) { return $m2; }
		if ($h*3 < 2) { return $m1 + ($m2 - $m1)*(2 / 3 - $h) * 6; }
		return $m1;
	}
	
	/**	
	 * Convert HSL to RGB

	 * @param	array		$hsl	3 floats beetween 0.0 and 1.0
	 *
	 * @return array				3 floats beetween 0.0 and 1.0
	 */
	static private function hsl2rgb($hsl)
	{
		$h = $hsl[0];
		$s = $hsl[1];
		$l = $hsl[2];

		if ($s == 0.0) {
			$r = $g = $b = $l;
		} else {
			if ($l <= 0.5) {
				$m2 = $l * ($s + 1);
			} else {
				$m2 = $l + $s -($l * $s);
			}
			$m1 = $l * 2 - $m2;
			$r = self::hue($m1, $m2, ($h + 1 / 3));
			$g = self::hue($m1, $m2, $h);
			$b = self::hue($m1, $m2, ($h - 1 / 3));
		}
		return array($r, $g, $b);
	}
	
	
	/**
	* Convert RGB colors array into HSL array
	* 
	* @param array 		$rgb 	RGB colors set	3 floats beetween 0.0 and 1.0
	* @return array 			HSL set			3 floats beetween 0.0 and 1.0
	*/
	function rgb2hsl($rgb)
	{	
		$clrR = $rgb[0];
		$clrG = $rgb[1];
		$clrB = $rgb[2];
		
		$clrMin = min($clrR, $clrG, $clrB);
		$clrMax = max($clrR, $clrG, $clrB);
		$deltaMax = $clrMax - $clrMin;
		
		$L = ($clrMax + $clrMin) / 2;
		
		if (0 == $deltaMax){
			$H = 0;
			$S = 0;
			}
		else{
			if (0.5 > $L){
				$S = $deltaMax / ($clrMax + $clrMin);
				}
			else{
				$S = $deltaMax / (2 - $clrMax - $clrMin);
				}
			$deltaR = ((($clrMax - $clrR) / 6) + ($deltaMax / 2)) / $deltaMax;
			$deltaG = ((($clrMax - $clrG) / 6) + ($deltaMax / 2)) / $deltaMax;
			$deltaB = ((($clrMax - $clrB) / 6) + ($deltaMax / 2)) / $deltaMax;
			if ($clrR == $clrMax){
				$H = $deltaB - $deltaG;
				}
			else if ($clrG == $clrMax){
				$H = (1 / 3) + $deltaR - $deltaB;
				}
			else if ($clrB == $clrMax){
				$H = (2 / 3) + $deltaG - $deltaR;
				}
			if (0 > $H) $H += 1;
			if (1 < $H) $H -= 1;
			}
		return array($H, $S, $L);
	}
	
	
	
	/**
	* Convert YUV colors array into RGB array
	* 
	* @param array $yuv 		YUV colors set
	* @return array 			RGB set
	*/
	private function yuv2rgb($yuv)
	{
		$rgb = array(
			$yuv[0] - 0.0009267*($yuv[1]-0.5) + 1.4016868*($yuv[2]-0.5),
			$yuv[0] -  0.3436954*($yuv[1]-0.5) - 0.7141690*($yuv[2]-0.5),
			$yuv[0] +  1.7721604*($yuv[1]-0.5) + 0.0009902*($yuv[2]-0.5)
		);
		foreach ($rgb as &$component) {
			if ($component < 0) {
				$component = 0;
			} elseif ($component > 1) {
				$component = 1;
			}
		}
		
		
		
		return $rgb;
	}
	
	/**
	 * set color in RGB space
	 *
	 * @param	int		$r	number beetween 0 and 1
	 * @param	int		$g	number beetween 0 and 1
	 * @param	int		$b	number beetween 0 and 1
	 */
	public function setRGB($r, $g, $b) {
		$this->color_method = 'RGB';
		$this->color = array($r, $g, $b);
		return $this;
	}

	/**	
	 * Set color in HSL space
	 *
	 * @param	int		$h	number beetween 0 and 1
	 * @param	int		$s	number beetween 0 and 1
	 * @param	int		$l	number beetween 0 and 1
	 *
	 * @return Widget_Color
	 */
	public function setHSL($h, $s, $l) {
		$this->color_method = 'HSL';
		$this->color = array($h, $s, $l);
		return $this;
	}

	/**
	 * set color in YUV space
	 *
	 * @param	int		$y	number beetween 0 and 1
	 * @param	int		$u	number beetween 0 and 1
	 * @param	int		$v	number beetween 0 and 1
	 */
	public function setYUV($y, $u, $v) {
		$this->color_method = 'YUV';
		$this->color = array($y, $u, $v);
		return $this;
	}

	/**
	 * @return array
	 */
	public function getRGB() {
		switch($this->color_method) {
			case 'HSL':
				return self::hsl2rgb($this->color);
				
			case 'YUV':
				return self::yuv2rgb($this->color);
				
			case 'RGB':
				return $this->color;
		}
		
		return null;
	}
	
	/**
	 * @return array
	 */
	public function getHSL() {
		switch($this->color_method) {
			case 'HSL':
				return $this->color;
				
			case 'YUV':
				return self::rgb2hsl(self::yuv2rgb($this->color));
				
			case 'RGB':
				return self::rgb2hsl($this->color);
		}
		
		return null;
	}
	
	/**
	 * set color in RGB space with hexadecimal value (without #)
	 *
	 * @param	string		$hexa
	 */
	public function setHexa($hexa) {
		$decimal = hexdec($hexa);
		$r = ($decimal & 0xFF0000) >> 16;
		$g = ($decimal & 0xFF00) >> 8;
		$b = $decimal & 0xFF;
		return $this->setRGB($r, $g, $b);
	}

	
	/**
	 * get RVB hexadecimal code without #
	 * @return string
	 */
	public function getHexa() {
		$rgb = $this->getRGB();
		
		if (null === $rgb) {
			return null;
		}
		
		return sprintf('%02X%02X%02X', round(255 * $rgb[0]), round(255 * $rgb[1]), round(255 * $rgb[2]));
	}
	
	/**
	 * Create a color from a string
	 * set HSL color with hue from string
	 * @param	string	$str
	 * @param	int		$s	 	saturation : number beetween 0 and 100
	 * @param	int		$l		lightness : number beetween 0 and 100
	 *
	 * @return Widget_Color
	 */
	public function setHueFromString($str, $s, $l) {
	
		// $h = (360 * (ord($str{0}) << 24 | ord($str{1}) << 16 | ord($str{2}) << 8 | ord($str{3}))) / 0xFFFFFFFF;
	
		$h = (abs(crc32($str))) / 0x7FFFFFFF;
		$this->setHSL($h, $s, $l);
		return $this;
	}
}

